﻿using farming.Admins.Dto;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using farming.Utility;
using System.Security.Claims;
using Microsoft.Extensions.Configuration;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
using IdentityModel;
using System.IO;
using Lazy.Captcha.Core;

namespace farming.Admins
{
    [ApiExplorerSettings(GroupName = "v1")]
    [Authorize]
    public class AdminService : ApplicationService
    {
        private readonly IRepository<Admin> repository;
        private readonly IHttpContextAccessor httpContext;
        private readonly IConfiguration configuration;
        private readonly ICaptcha captcha;

        public AdminService(
            IRepository<Admin> repository,
            IHttpContextAccessor httpContext,
            IConfiguration configuration,
            ICaptcha captcha
            )
        {
            this.repository = repository;
            this.httpContext = httpContext;
            this.configuration = configuration;
            this.captcha = captcha;
        }

        /// <summary>
        /// 创建用户
        /// </summary>
        /// <param name="createDto"></param>
        /// <returns></returns>
        [HttpPost("/Admin/Create")]
        public async Task<RegisterResultDto> CreateAsync(CreateUpdateAdminDto createDto)
        {
            try
            {
                var admin = await repository.FirstOrDefaultAsync(m => m.UserName == createDto.UserName);
                if (admin != null)
                {
                    return new RegisterResultDto { Code = RegisterState.UserNameExists, Message = RegisterState.UserNameExists.EnumToDescription() };
                }
                createDto.Password = createDto.Password.Md5();
                var entity = ObjectMapper.Map<CreateUpdateAdminDto, Admin>(createDto);
                entity.IsLock = false;
                await repository.InsertAsync(entity);

                #region 插入角色数据
                //插入角色数据
                /*var roles = createDto.Role.Select(m => new AdminRole
                {
                    AdminId = entity.Id,
                    RoleId = m
                });

                await repositoryAdminrole.InsertManyAsync(roles);*/
                #endregion
                return new RegisterResultDto { Code = RegisterState.Success, Message = RegisterState.Success.EnumToDescription() };
            }
            catch (Exception e)
            {
                return new RegisterResultDto { Code = RegisterState.Failed, Message = e.Message };
            }
        }

        /// <summary>
        /// 验证码
        /// </summary>
        /// <returns></returns>
        [HttpGet("/Admin/Captcha")]
        [AllowAnonymous]
        public ResultDto<CaptchaDto> Captcha()
        {
            string guid = $"captcha:{Guid.NewGuid().ToString("N")}";
            var info = captcha.Generate(guid);
            httpContext.HttpContext.Response.Cookies.Append("ValidateCode", guid);
            var stream = new MemoryStream(info.Bytes);

            return new ResultDto<CaptchaDto>
            {
                Code = ResultState.Success,
                Data = new CaptchaDto
                {
                    captchaBase64 = $"data:image/gif;base64,{Convert.ToBase64String(stream.ToArray())}",
                    captchaKey = guid
                }
            };
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="adminDto"></param>
        /// <returns></returns>
        [HttpPost("/Admin/Login")]
        [AllowAnonymous]
        public async Task<LoginResultDto<TokenDto>> LoginAsync([FromForm] LoginDto adminDto)
        {
            try
            {
                if (!captcha.Validate(httpContext.HttpContext.Request.Cookies["ValidateCode"], adminDto.captchaCode))
                {
                    return new LoginResultDto<TokenDto>
                    {
                        Code = LoginState.CaptchaCodeError,
                        Message = LoginState.CaptchaCodeError.EnumToDescription()
                    };
                }
                var admin = await repository.FirstOrDefaultAsync(m => m.UserName == adminDto.UserName);
                if (admin == null)
                {
                    return new LoginResultDto<TokenDto> { Code = LoginState.NotFoundUserName, Message = LoginState.NotFoundUserName.EnumToDescription() };
                }
                else
                {
                    //如果达到解锁条件，则更新锁定状态
                    if (admin.IsLock && DateTime.Now.Subtract((DateTime)admin.LockTime).TotalSeconds > 30)
                    {
                        admin.IsLock = false;
                        admin.LockTime = null;
                        admin.ErrorLoginNum = 0;
                        await repository.UpdateAsync(admin);
                    }

                    //锁定时间小于30分钟并且在锁定状态
                    if (admin.IsLock && DateTime.Now.Subtract((DateTime)admin.LockTime).TotalSeconds < 30)
                    {
                        return new LoginResultDto<TokenDto> { Code = LoginState.Locked, Message = LoginState.Locked.EnumToDescription() };
                    }
                    else
                    {
                        if (admin.Password != adminDto.Password.Md5())
                        {
                            admin.ErrorLoginNum += 1;

                            if (admin.ErrorLoginNum >= 5)
                            {
                                admin.IsLock = true;
                                admin.LockTime = DateTime.Now;

                                //锁定用户
                                await repository.UpdateAsync(admin);



                                return new LoginResultDto<TokenDto> { Code = LoginState.Locked, Message = LoginState.Locked.EnumToDescription() };
                            }

                            return new LoginResultDto<TokenDto> { Code = LoginState.PasswordWrong, Message = LoginState.PasswordWrong.EnumToDescription() };
                        }
                        else
                        {
                            //更新末次登录IP和末次登录时间
                            admin.LastLoginIp = httpContext.HttpContext.Connection.RemoteIpAddress.MapToIPv4().ToString();
                            admin.LastLoginTime = DateTime.Now;
                            admin.ErrorLoginNum = 0;
                            await repository.UpdateAsync(admin);

                            //调用生成Token方法
                            var authInfo = await GenerateToken(admin);

                            return new LoginResultDto<TokenDto>
                            {
                                Code = LoginState.Success,
                                Data = authInfo
                            };
                        }
                    }
                }
            }
            catch (Exception e)
            {
                return new LoginResultDto<TokenDto> { Code = LoginState.Failed, Message = e.Message };
            }
        }

        /// <summary>
        /// 获取用户信息
        /// </summary>
        /// <returns></returns>
        [HttpGet("/Admin/Info")]
        public async Task<ResultDto<PermissionDto>> Info()
        {
            return new ResultDto<PermissionDto>
            {
                Code = ResultState.Success,
                Data = new PermissionDto
                {
                    Avatar = "https://oss.youlai.tech/youlai-boot/2023/05/16/811270ef31f548af9cffc026dfc3777b.gif",
                    Nickname = "系统管理员",
                    Perms = new string[] {
                            "sys:menu:delete",
                            "sys:dept:edit",
                            "sys:dict_type:add",
                            "sys:dict:edit",
                            "sys:dict:delete",
                            "sys:dict_type:edit",
                            "sys:menu:add",
                            "sys:user:add",
                            "sys:role:edit",
                            "sys:dept:delete",
                            "sys:user:password_reset",
                            "sys:user:edit",
                            "sys:user:delete",
                            "sys:dept:add",
                            "sys:role:delete",
                            "sys:dict_type:delete",
                            "sys:menu:edit",
                            "sys:dict:add",
                            "sys:role:add"
                     },
                    Roles = new string[] { "ADMIN" },
                    UserId = 1770328009396588544,
                    Username = "admin"
                }
            };
        }

        private async Task<TokenDto> GenerateToken(Admin admin)
        {
            IList<Claim> claims = new List<Claim> {
                                new Claim(JwtClaimTypes.Name, ""),
                                new Claim(nameof(Admin.Introduction),admin.Introduction),
                            };

            //JWT密钥
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["JwtConfig:Bearer:SecurityKey"]));

            //算法
            var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            //过期时间
            DateTime expires = DateTime.UtcNow.AddDays(10);

            //Payload负载
            var token = new JwtSecurityToken(
                issuer: configuration["JwtConfig:Bearer:Issuer"],
                audience: configuration["JwtConfig:Bearer:Audience"],
                claims: claims,
                notBefore: DateTime.UtcNow,
                expires: expires,
                signingCredentials: cred
                );

            var handler = new JwtSecurityTokenHandler();

            //生成令牌
            string jwt = handler.WriteToken(token);

            return new TokenDto
            {
                accessToken = jwt,
                expires = expires,
                refreshToken = null,
                tokenType = "Bearer"
            };
        }
    }
}
